package com.hmall.search.service.impl;

import cn.hutool.core.util.ObjectUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.FunctionBoostMode;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.json.JsonData;
import com.hmall.common.domain.PageDTO;
import com.hmall.search.domain.po.ItemDoc;
import com.hmall.search.domain.query.ItemPageQuery;
import com.hmall.search.service.ISearchService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service
@Slf4j
@AllArgsConstructor
public class SearchServiceImpl implements ISearchService {

    private final ElasticsearchClient esClient;


    @Override
    public PageDTO<ItemDoc> search(ItemPageQuery query) throws IOException {

        SearchResponse<ItemDoc> response = esClient.search(searchBuilder -> searchBuilder
                .index("items")
                .query(qbuilder -> qbuilder
                        .functionScore(fsbuilder -> fsbuilder
                                .query(qb -> qb
                                        .bool(boolbuilder -> {

                                                    if (ObjectUtil.isNotEmpty(query.getKey())) {
                                                        boolbuilder.must(mt -> mt.match(mb -> mb.field("name").query(query.getKey())));

                                                    }
                                                    if (ObjectUtil.isNotEmpty(query.getCategory())) {
                                                        boolbuilder.filter(ft -> ft.term(tm -> tm.field("category").value(query.getCategory())));
                                                    }
                                                    if (ObjectUtil.isNotEmpty(query.getBrand())) {
                                                        boolbuilder.filter(ft -> ft.term(tm -> tm.field("Brand").value(query.getBrand())));
                                                    }
                                                    if (ObjectUtil.isNotEmpty(query.getMinPrice())) {
                                                        boolbuilder.filter(ft -> ft.range(rg -> rg.field("price").gte(JsonData.of(query.getMinPrice()))));

                                                    }
                                                    if (ObjectUtil.isNotEmpty(query.getMaxPrice())) {
                                                        boolbuilder.filter(ft -> ft.range(rg -> rg.field("price").gte(JsonData.of(query.getMaxPrice()))));

                                                    }
                                                    return boolbuilder;
                                                }
                                        ))
                                .functions(fcbuilder -> fcbuilder
                                        .filter(ft -> ft.
                                                term(tm -> tm.field("isAD").value(true)))
                                        .weight(100D))
                                .boostMode(FunctionBoostMode.Multiply)))
                .sort(sortBuilder -> sortBuilder
                        .field(fieldBuilder -> {
                            if (ObjectUtil.isEmpty(query.getSortBy())) {

                                fieldBuilder.field("_score")
                                        .order(SortOrder.Desc);

                            } else {
                                fieldBuilder.field(query.getSortBy())
                                        .order(query.getIsAsc() ? SortOrder.Asc : SortOrder.Desc);
                            }
                            return fieldBuilder;
                        }))
                .from(query.getPageSize() * (query.getPageNo() - 1)).size(query.getPageSize())
                .highlight(highlightBuilder -> highlightBuilder
                        .fields("name", fieldBuilder -> fieldBuilder
                                .preTags("<em style ='color:red;'>")
                                .postTags("</em>"))), ItemDoc.class);
        PageDTO<ItemDoc> page = new PageDTO<>();
        long total = response.hits().total().value();
        page.setTotal(total);
        List<Hit<ItemDoc>> hits = response.hits().hits();
        List<ItemDoc> docList = hits.stream().map(hit -> {
            ItemDoc itemDoc = hit.source();
            Map<String, List<String>> highlight = hit.highlight();
            if (ObjectUtil.isNotEmpty(highlight)) {
                List<String> nameValues = highlight.get("name");
                if (ObjectUtil.isNotEmpty(nameValues)) {
                    itemDoc.setName(nameValues.get(0));
                }
            }
            return itemDoc;
        }).collect(Collectors.toList());
        page.setList(docList);
        return page;
    }
}
